# ===----------------------------------------------------------------------=== #
# Copyright (c) 2025, Modular Inc. All rights reserved.
#
# Licensed under the Apache License v2.0 with LLVM Exceptions:
# https://llvm.org/LICENSE.txt
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ===----------------------------------------------------------------------=== #

from sys.ffi import c_char, external_call

from .pwd import Passwd

comptime uid_t = Int32
comptime gid_t = Int32
comptime char = UnsafePointer[c_char, MutOrigin.external]


@register_passable("trivial")
struct _C_Passwd:
    var pw_name: char
    var pw_passwd: char
    var pw_uid: uid_t
    var pw_gid: gid_t
    var pw_gecos: char
    var pw_dir: char
    var pw_shell: char


fn _build_pw_struct(
    passwd_ptr: UnsafePointer[mut=False, _C_Passwd]
) raises -> Passwd:
    var c_pwuid = passwd_ptr[]
    return Passwd(
        pw_name=String(unsafe_from_utf8_ptr=c_pwuid.pw_name),
        pw_passwd=String(unsafe_from_utf8_ptr=c_pwuid.pw_passwd),
        pw_uid=Int(c_pwuid.pw_uid),
        pw_gid=Int(c_pwuid.pw_gid),
        pw_gecos=String(unsafe_from_utf8_ptr=c_pwuid.pw_gecos),
        pw_dir=String(unsafe_from_utf8_ptr=c_pwuid.pw_dir),
        pw_shell=String(unsafe_from_utf8_ptr=c_pwuid.pw_shell),
    )


fn _getpw_linux(uid: UInt32) raises -> Passwd:
    var passwd_ptr = external_call[
        "getpwuid", UnsafePointer[_C_Passwd, MutOrigin.external]
    ](uid)
    if not passwd_ptr:
        raise Error("user ID not found in the password database: ", uid)
    return _build_pw_struct(passwd_ptr)


fn _getpw_linux(var name: String) raises -> Passwd:
    var passwd_ptr = external_call[
        "getpwnam", UnsafePointer[_C_Passwd, MutOrigin.external]
    ](name.as_c_string_slice().unsafe_ptr())
    if not passwd_ptr:
        raise Error("user name not found in the password database: ", name)
    return _build_pw_struct(passwd_ptr)
